Skip to content

PR5/8: Adding scaling distribution to hwgraph#124

Merged
anisse merged 5 commits into
mainfrom
hwgraph-scaling-distribution
Jul 24, 2026
Merged

PR5/8: Adding scaling distribution to hwgraph#124
anisse merged 5 commits into
mainfrom
hwgraph-scaling-distribution

Conversation

@ErwanAliasr1

Copy link
Copy Markdown
Collaborator

This PR adds some per-core and per numa distributions graphs

@ErwanAliasr1 ErwanAliasr1 changed the title PR4/8: Adding scaling distribution to hwgraph PR5/8: Adding scaling distribution to hwgraph Jul 15, 2026
@ErwanAliasr1
ErwanAliasr1 force-pushed the hwgraph-scaling-distribution branch from 73fc3b1 to 62bd4d9 Compare July 16, 2026 10:32
@anisse
anisse requested a review from Arno500 July 24, 2026 08:52
@anisse
anisse force-pushed the hwgraph-scaling-distribution branch from 62bd4d9 to bbbb9c3 Compare July 24, 2026 08:54
@anisse
anisse self-requested a review July 24, 2026 08:56
ErwanAliasr1 and others added 5 commits July 24, 2026 11:08
Reading a value off the smp_scaling line graphs was imprecise with only the
major Y ticks.

Add a single intermediate horizontal gridline between two Y
ticks (AutoMinorLocator(2)), a bit bolder than the default minor grid so it is
actually readable, but still lighter than the solid major gridlines.

Applies to the scaling line graphs (perf, perf_watt, watts, cpu_clock, cpu_ipc); the
delta heatmaps are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Erwan Velu <e.velu@criteo.com>
The per-trace legend of the smp_scaling graphs shows, for each trace,
"<name> [min; mean; stddev; max]". Each label was padded to its own length,
so traces with different name lengths produced a misaligned table where the
[min; mean; stddev; max] columns did not line up, making the values harder to
read and compare between traces.

Pad the trace name and the values to a width common to all the traces of the
graph (like the environment graphs already do), so the columns stay aligned
whatever the trace names.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
For every per-core CPU metric (Core frequency, Core IPC and CPU Core
power consumption), render an additional graph showing how that metric
is distributed across the cores at steady state. Each core's mean value
over the run becomes one data point; a violin shows the density and an
overlaid box shows the median (red), mean (green dashed), quartiles and
outliers.

Where the line graphs answer "how did the metric evolve over time?",
these answer "how uniform were the cores?" -- immediately exposing
stragglers, bimodal behaviour (e.g. boosted vs throttled cores) and the
spread that a single averaged curve hides.

Like the other per-core graphs they are rendered twice, once over all
the cores (all_cores) and once restricted to the cores pinned during the
job (pinned_cores), and land in the same per-metric directories next to
their line graphs. The Y axis is autoscaled rather than zero-based: a
distribution is unreadable squished against a zero baseline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Erwan Velu <e.velu@criteo.com>
Mirror the per-core steady-state distribution graphs on the SMP scaling
views. For each trace and each per-core metric (Core frequency, Core IPC
and CPU Core power consumption), one graph plots a violin + box per
scaling step (X = worker count, evenly spaced), showing how the
core-to-core distribution of that metric evolves as the sweep grows.

The scaling line graphs plot a single averaged value per step; these
expose the spread that average hides -- cores that start to diverge or
throttle only past a given worker count, bimodal frequency behaviour, or
a widening per-core power spread. The box reports median (red), mean
(green dashed), quartiles and outliers.

Like the other per-core scaling graphs they are rendered for all_cores
and, when the sweep pins cores, pinned_cores, landing in the cpu_clock,
cpu_ipc and cpu_core_power directories next to the matching line graphs.
The Y axis is autoscaled rather than zero-based: a distribution is
unreadable squished against a zero baseline.

Why violin graphs at both levels: the per-benchmark (steady-state) and
the per-scaling-step distributions answer two complementary questions
that averages and time-series curves both flatten.

  - The individual, steady-state violin answers "for this one operating
    point, how uniform is the hardware?". A tight body means every core
    behaves alike; a long tail or a second lobe exposes a straggler, an
    asymmetric NUMA/boost domain or a mis-pinned core -- something a
    single mean value, and even the time-series line graph, hides because
    they collapse every core into one number per instant.

  - The scaling violins put those same distributions side by side along
    the load axis, so the shape itself becomes the signal: you watch the
    spread widen or split exactly at the worker count where cores begin
    to contend for power/thermal budget, and you can tell a uniform
    slow-down (body drops as a block) from a divergence (body stretches
    or splits) -- a distinction a scaling line of per-step averages
    cannot make.

Together they let a reader first confirm a single point is healthy, then
follow how that health degrades under increasing load, using the same
visual vocabulary at both zoom levels.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Erwan Velu <e.velu@criteo.com>
Add a distribution view for per-core CPU metrics (frequency, IPC, core
power) aggregated by NUMA domain, complementing the existing per-domain
line graphs and heatmaps:

- numa_distribution_graph: one violin + box per NUMA domain for a single
  benchmark job (steady-state), landing next to the matching line graph
  in the same all_numa/pinned_numa directories.

- render_numa_scaling_ridgelines: the SMP-scaling counterpart. A first
  grouped-violin attempt (one violin per domain per step, all in one
  axes) became unreadable past a handful of domains and steps. After
  reviewing sample renderings of several alternatives (median+IQR line,
  small multiples, spread heatmap, ridgeline), the ridgeline design was
  picked: one panel per scaling step -- every step, laid out as a grid
  so the figure grows in rows rather than becoming unreadable -- each
  panel a stacked density (ridgeline) per NUMA domain, preserving the
  full distribution shape (skew, bimodality) that a single averaged
  value would flatten. The grid's header/footer are reserved as a
  constant number of inches (not a fraction of the figure) so they keep
  the same size regardless of how many rows a long sweep needs.

Both are rendered for all_numa (every core of each domain) and, when
the sweep pins cores, pinned_numa.

Also mark which CPU package each NUMA domain belongs to: hwbench does
not record this directly, but same-package domains are always much
closer to each other in the NUMA distance matrix than cross-package
ones, so _numa_domains_by_package groups domains whose mutual distance
is below a fixed threshold (union-find), with no need to know the
socket count up front. Each scaling ridgeline panel gets a pale
background wash per package behind its ridges, with a
"CPU package <n>" legend, colour-matched to the washes, centered below
the whole grid.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Erwan Velu <e.velu@criteo.com>
@anisse
anisse force-pushed the hwgraph-scaling-distribution branch from bbbb9c3 to cd9adbf Compare July 24, 2026 09:08
@anisse
anisse merged commit 9eadfc2 into main Jul 24, 2026
3 checks passed
@anisse
anisse deleted the hwgraph-scaling-distribution branch July 24, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants